package me.yxy.mobanddd.domain.shipment;

import me.yxy.mobanddd.domain.transportorder.TransportOrder;
import me.yxy.mobanddd.domain.warehouse.Warehouse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.*;

/**
 * 调度单确认
 */
@Service
@Transactional
public class ShipmentComfirmSupporter {

    /**
     * 确认操作，需要处理以下业务
     * <ul>
     *     <li>运单配送顺序排序</li>
     *     <li>调度单总里程计算</li>
     *     <li>调度单出发与到达时间预估</li>
     *     <li>调度单费用计算</li>
     * </ul>
     * @param shipment
     */
    public void process(Shipment shipment){

        //一对多也可以美如画
        List<TransportOrder> transportOrders = shipment.getTransportOrders();
        if(ObjectUtils.isEmpty(transportOrders)){
            return;
        }

        //调整配送顺序
        sortOrders(transportOrders);

        //根据配送顺序,计算总里程
        int totalMileage = calculateMileage(transportOrders);
        shipment.setTotalDistance((double) totalMileage);

        //根据配送顺序计算到达时间
        int totalCostDuration = calculateDuration(transportOrders);
        shipment.setTotalDuration(totalCostDuration);

        //调度单费用计算
        int costFee = calculateFee(totalMileage,totalCostDuration);
        shipment.setTotalFee((double) costFee);

        shipment.setStatus(ShipmentStatus.COMFIRMED);
    }

    private int calculateFee(int totalMileage, int totalCostDuration) {
        return (int) (totalMileage * Math.random() + totalCostDuration * Math.random());
    }

    private int calculateDuration(List<TransportOrder> transportOrders) {

        int costTime = 0;
        for (int idx = 0; idx < transportOrders.size(); idx++){
            costTime += new Random().nextInt(120);
        }

        return costTime;
    }


    /**
     * 单独计算里程
     * @param shipment 需要计算总里程的调度单，请注意保持在事务中，这里不单独开启事务，以免误操作导致业务问题
     * @return
     */
    public int calculateMileage(Shipment shipment){
        return calculateMileage(shipment.getTransportOrders());
    }

    private int calculateMileage(List<TransportOrder> transportOrders) {

        int totalMileage = 0;

        TransportOrder firstOrder = transportOrders.get(0);
        Warehouse startWarehouse = firstOrder.getWarehouse();
        int distance = calculateDistance(startWarehouse.getLongitude(),startWarehouse.getLatitude(),firstOrder.getReceiveLongitude(),firstOrder.getReceiveLatitude());
        totalMileage += distance;

        if(transportOrders.size() > 2){
            for (int idx = 0; idx < transportOrders.size()-1; idx++){
                TransportOrder startPoint = transportOrders.get(idx);
                TransportOrder endPoint = transportOrders.get(idx+1);
                totalMileage += calculateDistance(startPoint.getReceiveLongitude(),startPoint.getReceiveLatitude(),endPoint.getReceiveLongitude(),endPoint.getReceiveLatitude());
            }
        }

        return totalMileage;
    }

    /**
     * 计算两点之间的距离（米）
     */
    private int calculateDistance(Double startLng, Double startLat, Double endLng, Double endLat) {
        return new Random((long)(startLng+startLat+endLat+endLng)).nextInt(10*1000);
    }

    private void sortOrders(List<TransportOrder> transportOrders) {

        //根据业务规则调整顺序，这里用随机打乱来模拟
        Collections.shuffle(transportOrders);

        int orderIdx = 1;
        for (TransportOrder transportOrder : transportOrders) {
            transportOrder.saveDeliveryOrder(orderIdx++);
        }

    }

}
